/* eslint-disable react/display-name */
import React, { Component, Fragment } from 'react'
import { inject, observer } from 'mobx-react/index'
import { Table, Select, Button, Tooltip, Popover, Pagination, Modal, Upload, message, Progress, Input, Form, Alert } from 'antd'
import { CopyToClipboard } from 'react-copy-to-clipboard'
import { UploadOutlined, InfoCircleFilled, LoadingOutlined } from '@ant-design/icons'
import uuid from 'uuid'
import moment from 'moment'
import _ from 'lodash'

import request from '@/Utils/fecth'
import { address } from '@/Utils/apiConfig'
import Empty from '@/pages/Dashboard/common/Empty/index'
import CodeEdit from '@/components/CodeEdit'
import IconFont from '@/components/IconFont'
import SearchInput from '@/components/SearchInput'
import { LANG_OPS, TOKEN } from '@/Utils/CONST.js'
import Event from '@/Utils/Event'
import { INSTALLCHAINCODE, DEPLOYCHAINCODE, UPGRADECHAINCODE, DELETECHAINCODE } from '@/Utils/socketName'
import { checkPermission } from '@/components/AuthComponent/utils'

import './index.less'

const Option = Select.Option
const { chaincode, leagueManagement: { getPrivateDataList }} = address
const _link = `${window.location.origin}/api/v1`
const confirm = Modal.confirm
const policyId = 'c0299a86-1bcc-4d5e-9de2-0e290254f64e'

@inject('SocketModel')
@observer
export default class ChainCode extends Component {
  constructor(props) {
    super(props)
    this.state = {
      defaultKey: 'local',
      selectedPeers: [],
      version: '',
      servicesList: [],
      status: '',
      total: 0,
      list: [], // 链码列表
      percent: 0,
      chaincodePath: '',
      parameters: [],
      createChainloading: false,
      contractFilename: '',
      inputValue: '',
      inputVisible: false,
      fileList: null, // 上传链码的文件
      peerData: [], // 节点列表
      channelData: [],
      logList: [], // 日志
      loading: true,
      imageUploading: false,
      refreshedTag: false,
      expandObj: {},
      filename: '',
      pageNo: 1, // 当前页
      pageSize: 10, // 每页的条数
      modalVisible: false, // 弹出框
      fileVisible: false,
      policyData: [], // 背书策略
      language: '', // 添加链码语言
      contractList: [], // 添加链码合约list
      privateList: [], // 私有数据集
    }
    this.openIds = []
    this.consortiumId = props.match.params.id
    this.searchValue = ''
    this.flag = ''
  }

  componentDidMount() {
    this.getChaincodeData() // 获取数据
    this.getPrivateList()
    Event.on(INSTALLCHAINCODE, this.refreshData)
    Event.on(DEPLOYCHAINCODE, this.refreshData)
    Event.on(UPGRADECHAINCODE, this.refreshData)
    Event.on(DELETECHAINCODE, this.refreshData)
  }

  componentWillUnmount() {
    Event.off(INSTALLCHAINCODE, this.refreshData)
    Event.off(DEPLOYCHAINCODE, this.refreshData)
    Event.off(UPGRADECHAINCODE, this.refreshData)
    Event.off(DELETECHAINCODE, this.refreshData)
  }

  /**
   * socket刷新数据
   */
  refreshData = async() => {
    this.getChaincodeData()
    const { expandObj } = this.state
    await Promise.all(this.openIds.map(async id => {
      const res = await request().get(chaincode.chaincodeSubList.format({ consortiumId: this.consortiumId, name: id }))
      if (res && res.status === 200) {
        expandObj[id] = res.data || []
      }
    }))
    this.setState({
      expandObj,
    })
  }

  /**
   * 私有数据集
   */
  getPrivateList = async() => {
    let res = await request().get(`${getPrivateDataList.format({ consortiumId: this.consortiumId })}`)
    if (res && res.status === 200) {
      this.setState({
        privateList: res.data || [],
      })
    }
  }

  onChangeUploadContract = async(info) => {
    const fileData = document.getElementById('uploadInput').files
    if (!fileData[0]) {
      return false
    } else {
      this.form && this.form.setFieldsValue({ path: '' })
      this.setState({
        status: true,
        percent: 0,
        imageUploading: true,
        filename: fileData[0] ? fileData[0].name : '',
        fileList: fileData[0] ? fileData[0] : '',
      })
      const formData = new FormData()
      formData.append('file', fileData[0])
      let res = await request().post(chaincode.upload, formData, {
        onUploadProgress: (progressEvent) => {
          let percent = Math.round((progressEvent.loaded * 100) / progressEvent.total)
          this.setState({
            percent,
          })
        },
      })
      if (res && res.status === 200) {
        this.form && this.form.setFieldsValue({ path: res.data.path })
        this.setState({
          imageUploading: false,
          status: true,
          percent: 100,
        })
      } else {
        this.setState({
          imageUploading: false,
          status: false,
          percent: 100,
        })
      }
    }
  }

  getChaincodeData = async() => {
    this.setState({
      loading: true,
    })
    let res = await request().get(
      `${chaincode.chaincodeList.format({ consortiumId: this.consortiumId })}${this.state.pageNo}/${this.state.pageSize}?name=${encodeURIComponent(this.searchValue || '')}`)
    this.setState({
      loading: false,
    })
    if (res && res.status === 200) {
      this.setState({
        list: res.data.data,
        total: res.data.total,
      })
    }
  }

  deleteCode = (record) => {
    // 状态正在删除则信息提示
    if (record && record.status === 'DELETING') {
      message.warn('该链码正在删除中，请勿重复操作')
      return
    }
    const _this = this
    const ops = {
      data: {
        consortiumId: this.consortiumId,
      },
    }
    confirm({
      title: '删除提示',
      className: 'common-confirm-small',
      icon: <InfoCircleFilled />,
      content: `确定要删除${record.name}链码吗？删除后，在链码列表也将不再可见！`,
      okText: '确定',
      cancelText: '取消',
      onOk: async() => {
        request().delete(chaincode.deleteChaincode.format({ chaincodeId: record.id }), ops).then(res => {
          const { data = {}, status } = res || {}
          if (status === 200) {
            if (data.status === 'success') {
              message.success('链码删除成功')
            } else {
              message.success('链码删除中')
            }
            // 成功之后重新查询下链码
            _this.getChaincodeData()
          } else {
            message.error(data.msg || '链码删除失败')
          }
          _this.refreshData() // 更新数据
        })
      },
      onCancel() {

      },
    })
  }

  // 重置 重置为初始状态
  clear = (clear, flag) => {
    let data = this.state[flag]
    data.map(element => {
      element.checked = false
    })
    this.setState({
      [flag]: data,
    })
    clear()
  }

  search = (val) => {
    this.searchValue = val
    this.setState({
      pageNo: 1,
    }, () => {
      this.getChaincodeData()
    })
  }

  onShowSizeChange = (current, pageSize) => {
    let pageNo = this.state.pageNo
    this.setState({
      pageSize,
      pageNo,
    }, () => {
      this.getChaincodeData()
    })
  }

  changePaginationFn = (pageNumber) => {
    this.setState({
      pageNo: pageNumber,
    }, () => this.getChaincodeData())
  }

  // 展开获取数据
  onExpand = async(expanded, record) => {
    const { expandObj } = this.state
    if (expanded && record.id) {
      this.openIds.push(record.id)
      const res = await request().get(chaincode.chaincodeSubList.format({ consortiumId: this.consortiumId, name: record.id }))
      if (res && res.status === 200) {
        expandObj[record.id] = res.data || []
        this.setState({
          expandObj,
        })
      }
    } else {
      this.openIds = this.openIds.filter(v => v !== record.id)
    }
  }

  handleCancel = () => {
    this.form = null
    this.setState({
      createChainloading: false,
      peerData: [],
      channelData: [],
      modalVisible: false,
    })
  }

  // 删除参数
  handleClose = (removedIndex) => {
    let { parameters } = this.state
    parameters.splice(removedIndex, 1)
    this.setState({
      parameters,
      refreshedTag: true,
    }, () => {
      this.setState({
        refreshedTag: false,
      })
    })
  };

  saveFile = () => {
    this.editForm && this.editForm.validateFields().then(async(values) => {
      const filename = values.filename + (`.${(this.form && this.form.getFieldValue('c_language')) || 'java'}`).replace('golang', 'go')
      const data = this.CodeEdit.getValue()
      let res = await request().post(chaincode.save, {
        filename,
        data,
      })
      if (res && res.status === 200) {
        const file = res.data || {}
        const fileList = [{
          ...file,
          uid: uuid(),
        }]
        this.setState({
          contractList: fileList,
          fileVisible: false,
        })
        this.form && this.form.setFieldsValue({
          contract: fileList,
        })
      }
    })
  }

  handleInputChange = (e) => {
    this.setState({ inputValue: e.target.value.trim() })
  };

  handleInputConfirm = () => {
    const state = this.state
    const inputValue = state.inputValue
    let parameters = state.parameters
    if (inputValue) {
      parameters = [...parameters, inputValue]
    }
    this.form && this.form.setFieldsValue({ args: parameters })
    this.setState({
      refreshedTag: true,
    }, function() {
      this.setState({
        parameters,
        inputVisible: false,
        inputValue: '',
        refreshedTag: false,
      })
    })
  }

  showInput = () => {
    this.setState({ inputVisible: true })
  }

  clearParameters = () => {
    this.setState({
      parameters: [],
    })
    this.form && this.form.setFieldsValue({ args: '' })
  }

  normFile = e => {
    if (Array.isArray(e)) {
      return e
    }
    return e && e.fileList
  };

  /**
   * openModal
   */
  setModal = async(record, flag, url, setstatekey) => {
    this.flag = flag
    this.record = record
    this.setState({
      parameters: [],
      logList: [],
      peerData: [],
      channelData: [],
      fileList: null,
      contractList: [],
      version: record.version,
      modalVisible: true,
    })
    if (flag === 'deploy' || flag === 'upgrade') {
      // 判断有数据就不重新请求
      let res1 = await request().get(chaincode.getPolicy.format({ consortiumId: this.consortiumId }))
      if (res1 && res1.status === 200) {
        this.setState({
          policyData: res1.data.data || res1.data, // 获取数据节点
        })
      } else {
        message.error('数据获取失败')
      }
    }
    if (url) {
      let res = await request().get(url)
      if (res && res.status === 200) {
        this.setState({
          [setstatekey]: res.data.data || res.data, // 获取数据节点
        })
      }
    }
  }

  openFileDialog = () => {
    this.setState({
      fileVisible: true,
    })
  }

  get modalParams() {
    const { language, contractList } = this.state
    const uploadProps = {
      fileList: contractList,
      accept: '.go,application/zip',
      beforeUpload: (file) => {
        // 限制.zip之后，.xlsx,.doc仍然可选，所以手动限制下
        const fileType = (this.form && this.form.getFieldValue('c_language')) || 'java'
        // 选择go语言可以选择go文件 其余的不可选
        const typeList = ['golang'].includes(fileType) ? ['.go', '.zip'] : ['.zip']
        return new Promise((resolve, reject) => {
          let fileName = file.name
          if (fileName.length > 25) {
            reject(file)
            return message.warn(`上传合约名称不得超过25个字符`)
          }
          let pos = fileName.lastIndexOf('.')
          let lastName = fileName.substring(pos, fileName.length)
          if (!typeList.includes(lastName.toLowerCase())) {
            message.warn(`仅支持上传${typeList.join(',')}格式`)
            reject(file)
          } else {
            resolve(file)
          }
        })
      },
      headers: { 'authorization': `Bearer ${localStorage.getItem(TOKEN)}` },
      action: chaincode.upload,
      maxCount: 1,
      onChange: (info) => {
        let fileList = info.fileList
        fileList = fileList.slice(-1) // 在这里控制上传文件的个数
        fileList.map(file => {
          if (file.response) {
            file.path = file.response.path || (file.response.data ? file.response.data.path : '')
          }
          return file
        })
        const file = fileList[0]
        if (file) {
          let percent = file.percent || 0
          let status = file.status || ''
          if (status === 'done' && percent === 100) {
            message.success(`${file.name}上传成功！`)
          }
        }
        this.setState({
          contractList: fileList,
        })
      },
    }
    return {
      'deploy': {
        parentClass: 'common-normal-modal',
        className: 'operation-log-modal upgrade-modal',
        title: '部署',
        timeout: true,
        footer: true,
        message: (message) => { return `部署${message}` },
        url: chaincode.upgrade.format({ chaincodeId: _.get(this.record, 'id'), type: this.flag }),
        postParams: (values) => {
          return Object.assign(values, {
            channelIds: values.channelIds.map(element => {
              return element.value
            }),
            consortiumId: this.consortiumId,
          })
        },
      },
      'install': {
        title: '安装',
        footer: true,
        parentClass: '',
        className: 'operation-log-modal upgrade-modal install-modal',
        timeout: true,
        message: (message) => { return `安装${message}` },
        url: chaincode.installChaincode.format({ chaincodeId: _.get(this.record, 'id') }),
        postParams: (values) => {
          return {
            nodes: values.nodes.map(element => { return element.value }),
          }
        },
        children:
          <Form
            onFinish={this.onFinish}
            className="ugrade-form"
            ref={ref => this.form = ref}
            colon={false}
            {...{
              labelCol: { span: 5 },
              wrapperCol: { span: 18 },
            }}
            hideRequiredMark={true}>
            <Form.Item
              label="标识："
            >
              <div className="desc">{_.get(this.record, 'name')}</div>
            </Form.Item>
            <Form.Item
              label="版本："
              name="version"
            >
              <div className="desc">{_.get(this.record, 'version')}</div>
            </Form.Item>
            <Form.Item
              label="选择节点："
              name="nodes"
              rules={[{ required: true, message: '请选择节点' }]}
            >
              <Select
                mode="multiple"
                showArrow={true}
                showSearch={false}
                placeholder="请选择节点"
                labelInValue
              >
                {
                  this.state.peerData.map(element => {
                    return (
                      <Select.Option key={element.id} value={element.id}>{element.name}</Select.Option>
                    )
                  })
                }
              </Select>
            </Form.Item>
          </Form>,
      },
      'upgrade': {
        title: '升级',
        parentClass: 'common-normal-modal',
        className: 'operation-log-modal upgrade-modal',
        footer: true,
        timeout: true,
        message: (message) => { return `升级${message}` },
        url: chaincode.upgrade.format({ chaincodeId: _.get(this.record, 'id'), type: this.flag }),
        postParams: (values) => {
          return Object.assign(values, {
            channelIds: values.channelIds.map(element => {
              return element.value
            }),
            consortiumId: this.consortiumId,
          })
        },
      },
      'addChaincode': {
        title: '添加链码',
        parentClass: 'common-modal-tab',
        className: `operation-log-modal upgrade-modal create-chain-modal ${this.state.defaultKey === 'service' ? 'service-modal' : ''}`,
        footer: this.state.defaultKey === 'local',
        url: chaincode.createChaincode,
        message: () => {
          return Modal.info({
            title: '已提交申请，请等待管理员审核',
            okText: '我知道了',
            onOk: () => {
            },
          })
        },
        width: 600,
        postParams: (values) => {
          const { contractList } = this.state
          return {
            ...values,
            consortiumId: this.consortiumId,
            c_policy_id: policyId,
            c_path: (contractList[0] || {}).path,
            contract: contractList,
          }
        },
        children:
          <div>
            <Form
              onFinish={this.onFinish}
              className="upload_chaincode_form_box"
              ref={ref => this.form = ref}
              colon={false}
              {...{
                labelCol: { span: 5 },
                wrapperCol: { span: 18 },
              }}
              hideRequiredMark={true}>
              <Form.Item
                name="c_display_name"
                label="合约名称："
                help="请输入合约名称，并且不超过25个字符"
                rules={[{ required: true, message: '请输入合约名称' }]}>
                <Input
                  className="input"
                  placeholder="请输入"
                  maxLength={25}
                />
              </Form.Item>
              <Form.Item
                name="c_name"
                label="标识："
                help="输入小写字母，数字，短连接线和点号，用于链上部署"
                rules={[
                  { required: true, message: '请输入标识' },
                  ({ getFieldValue }) => ({
                    validator(rule, value) {
                      let r = /^[-a-z.\d]+$/
                      if (value) {
                        if (!r.test(value)) {
                          return Promise.reject('只能输入小写字母，数字，短连接线，和点号！')
                        } else {
                          return Promise.resolve()
                        }
                      } else {
                        return Promise.resolve()
                      }
                    },
                  }),
                ]}>
                <Input
                  className="input"
                  placeholder="请输入"
                />
              </Form.Item>
              <Form.Item
                name="c_version"
                label="版本："
                help="输入小写字母，数字，短连接线和点号，用于链上部署"
                rules={[
                  { required: true, message: '请输入版本' },
                  () => ({
                    validator(rule, value) {
                      let r = /^[-a-z.\d]+$/
                      if (value) {
                        if (!r.test(value)) {
                          return Promise.reject('只能输入小写字母，数字，短连接线，和点号！')
                        } else {
                          return Promise.resolve()
                        }
                      } else {
                        return Promise.resolve()
                      }
                    },
                  }),
                ]}>
                <Input
                  className="input"
                  placeholder="请输入"
                  style={{ width: '100%' }}
                />
              </Form.Item>
              <Form.Item
                style={{ marginBottom: '20px' }}
                name="c_language"
                label="语言："
                rules={[
                  { required: true, message: '请选择语言' },
                ]}
              >
                <Select
                  placeholder={'请选择链码语言'}
                  className="policy-select"
                  onChange={(val) => {
                    this.setState({
                      language: val,
                      contractList: [],
                    })
                  }
                  }
                >
                  {
                    LANG_OPS.length && LANG_OPS.map(item => {
                      return (
                        <Option key={item} value={item}>{item}</Option>
                      )
                    })
                  }
                </Select>
              </Form.Item>
              <Form.Item className="form-item-required" label="上传合约：">
                <Form.Item
                  name="contract"
                  valuePropName="fileList"
                  getValueFromEvent={this.normFile}
                  rules={[
                    { required: !contractList.length, message: '请上传合约' },
                  ]}>
                  <Upload {...uploadProps}>
                    <Fragment>
                      <Button>
                        <UploadOutlined /> 上传合约
                      </Button>
                      <span style={{ marginLeft: '4px', fontSize: '12px', color: '#BBB' }}>合约名称不得超过25个字符</span>
                    </Fragment>
                  </Upload>
                </Form.Item>
                {
                  language === 'golang' && !contractList.length &&
                  <div style={{ marginTop: '8px' }}>
                    <a className="primary" onClick={this.openFileDialog} style={{ cursor: 'pointer' }}>自己创建合约</a>
                  </div>
                }
              </Form.Item>
              <Form.Item className="form-item-required" style={{ marginTop: 20 }} name="c_description" label="描述（选填）：">
                <Input.TextArea placeholder="请输入合约功能描述" className="description" />
              </Form.Item>
            </Form>
          </div>,
      },
      'document': {
        title: '调用技术文档',
        className: 'operation-log-modal document-modal',
        parentClass: 'common-normal-modal',
        children:
          <React.Fragment>
            <p className="api-address">动态接口地址</p>
            <div className="link">
              <Input value={_link} readOnly />
              <CopyToClipboard text={_link}
                onCopy={() => message.success('复制成功')}>
                <Button style={{ marginLeft: 8 }} className="com-btn-primary com-normal-btn">复制链接</Button>
              </CopyToClipboard>
            </div>
            <p className="see-document" onClick={() => this.props.history.push({ pathname: '/document' })}>
              查看文档
              <img src={require('@/images/chaincode/查看文档.svg')} />
            </p>

          </React.Fragment>,
      },
      'logs': {
        title: '失败日志',
        parentClass: '',
        className: 'operation-log-modal',
        width: 848,
        children:
          <div className="handle-scrollBar">
            <Table
              columns={this.logsColumns}
              dataSource={this.state.logList}
              pagination={false}
              rowKey={record => record._id}
            />
          </div>,
      },
    }
  }

  onFinish = async(values) => {
    this.setState({
      createChainloading: true,
    })
    let obj = this.modalParams[this.flag].postParams(values)
    let res = await request().post(this.modalParams[this.flag].url, obj)
    this.setState({
      createChainloading: false,
    })
    if (res && res.status === 200) {
      if (this.flag === 'addChaincode') {
        this.modalParams[this.flag].message()
      } else {
        if (this.modalParams[this.flag].timeout) {
          // 安装，部署，升级链码需要修改信息为XX中
          message.success(this.modalParams[this.flag].message('中'))
        } else {
          message.success(this.modalParams[this.flag].message('成功'))
        }
      }
      this.handleCancel()
      this.getChaincodeData()
      this.record && this.onExpand(true, this.record)
    }
  }

  // 渲染不同的modal
  renderModal = () => {
    const { policyData, parameters, refreshedTag, inputVisible, modalVisible } = this.state
    return (
      <Modal
        centered
        maskClosable={false}
        destroyOnClose
        className={`${_.get(this.modalParams[this.flag], 'parentClass')}`}
        getContainer={() => document.getElementById('chaincode-page')}
        wrapClassName={`${_.get(this.modalParams[this.flag], 'className')}`}
        title={_.get(this.modalParams[this.flag], 'title')}
        width={_.get(this.modalParams[this.flag], 'width')}
        footer={
          _.get(this.modalParams[this.flag], 'footer') &&
           <Fragment>
             <Button className="com-normal-btn com-btn-secondary" key="back" onClick={() => this.handleCancel()} disabled={this.state.createChainloading}>取 消</Button>
             <Button className="com-btn-primary com-normal-btn" type="primary" key="submit" onClick={() => this.form && this.form.submit()} loading={this.state.createChainloading}>确 认</Button>
           </Fragment>
        }
        onCancel={this.handleCancel}
        visible={modalVisible}
      >
        {
          _.get(this.modalParams[this.flag], 'children')
            ? _.get(this.modalParams[this.flag], 'children')
            : <Form
              onFinish={this.onFinish}
              initialValues={{
                channelIds: [],
                version: _.get(this.record, 'version'),
              }}
              className="ugrade-form"
              ref={ref => this.form = ref}
              colon={false}
              {...{
                labelCol: { span: 5 },
                wrapperCol: { span: 18 },
              }}
              hideRequiredMark={true}>
              {
                this.flag === 'deploy' &&
                <Alert showIcon message={
                  // (orgObj.performance[spec] || '标准版') === '标准版'
                  //   ? '注意！标准版链码部署上限为10个'
                  //   : '注意！企业版链码部署上限为20个。'
                  '注意！链码部署上限为20个。'
                } type="warning" />
              }
              <Form.Item
                label="标识："
              >
                <div className="desc">{_.get(this.record, 'name')}</div>
              </Form.Item>
              <Form.Item
                label="版本："
                name="version"
                rules={[
                  {
                    required: this.flag !== 'deploy', message: '请输入版本',
                  },
                  () => ({
                    validator(rule, value) {
                      let r = /^[-a-z.\d]+$/
                      if (value) {
                        if (!r.test(value)) {
                          return Promise.reject('只能输入小写字母，数字，短连接线，和点号！')
                        } else {
                          return Promise.resolve()
                        }
                      } else {
                        return Promise.resolve()
                      }
                    },
                  }),
                ]}>
                {
                  this.flag === 'deploy'
                    ? <div className="desc">{_.get(this.record, 'version')}</div>
                    : <Input
                      className="input"
                      placeholder="请输入版本"
                    />
                }

              </Form.Item>
              <Form.Item
                label="参数："
              >
                <Form.Item
                  name="args"
                  noStyle
                >
                  <span className="params-wrap">
                    {
                      !refreshedTag && parameters &&
                      parameters.map((parameter, index) => {
                        const isLongTag = parameter.length > 10
                        const tagElem = (
                          <span className="parameter-tag" key={index}>
                            {isLongTag ? `${parameter.slice(0, 20)}...` : parameter}
                            <img src={require('@/images/chaincode/remove.svg')} alt="" style={{ marginLeft: 4.7, cursor: 'pointer' }} onClick={() => this.handleClose(index)} />
                          </span>
                        )
                        return isLongTag ? <Tooltip overlayClassName="api-tooltip-style" title={parameter} key={index + 'io'}>{tagElem}</Tooltip> : tagElem
                      })
                    }
                    {
                      inputVisible && (
                        <Input
                          ref={this.saveInputRef}
                          type="text"
                          size="small"
                          className="params-input"
                          style={{ width: 88, marginRight: 4 }}
                          value={this.state.inputValue}
                          placeholder="请输入"
                          onChange={this.handleInputChange}
                          onBlur={this.handleInputConfirm}
                          onPressEnter={this.handleInputConfirm}
                        />
                      )
                    }
                    {
                      !inputVisible &&
                      <span onClick={this.showInput} className="add">+ 添加</span>
                    }
                    {
                      parameters.length > 0 &&
                      <span className="clear" onClick={this.clearParameters}>全部清除</span>
                    }
                  </span>
                </Form.Item>
              </Form.Item>
              <Form.Item
                label="背书策略："
                name="policyId"
                rules={[{ required: true, message: '请选择背书策略' }]}>
                <Select
                  placeholder={'请选择背书策略'}
                  className="policy-select"
                >
                  {
                    policyData.length && policyData.map(item => {
                      return (
                        <Option key={item.id} value={item.id}>{item.name}</Option>
                      )
                    })
                  }
                </Select>
              </Form.Item>
              <Form.Item
                label="部署通道："
                name="channelIds"
                rules={[{ required: true, message: '请选择部署通道' }]}
                extra={<span style={{ fontSize: '12px' }}>链码安装成功后才能选择通道实例化</span>}
              >
                <Select
                  mode="multiple"
                  labelInValue
                  placeholder="请选择部署通道"
                  showArrow={true}
                  showSearch={false}
                >
                  {
                    this.state.channelData.map(element => {
                      return (
                        <Option key={element.channel_id} value={element.channel_id}>{element.name}</Option>
                      )
                    })
                  }
                </Select>
              </Form.Item>
              {
                this.flag !== 'deploy' &&
                <Form.Item
                  label="上传链码："
                  name="path"
                  help="请保持和旧版本链码文件类型一致，否则可能出现升级失败"
                  rules={[{ required: true, message: '请上传链码' }]}
                >
                  <Form.Item noStyle
                  >
                    <div style={{ position: 'relative' }}>
                      <Button className="upload-btn" onClick={() => document.getElementById('uploadInput').click()}>
                        <UploadOutlined color="rgba(23,30,45,0.6)" /> <span>上传链码</span>
                      </Button>
                      {
                        this.state.fileList
                          ? <div className="file-list">
                            {
                              this.state.imageUploading
                                ? <LoadingOutlined color="#BDBDBD" />
                                : <img style={{ marginRight: 4 }} src={this.state.status ? require('@/images/chaincode/uploadSuccess.svg') : require('@/images/chaincode/uploadError.svg')} />
                            }
                            <div className="filename">
                              <div style={{ color: this.state.status ? 'rgba(23,30,45,0.65)' : '#E53232' }}> {this.state.filename}</div>
                              {
                                this.state.imageUploading || !this.state.status
                                  ? <Progress percent={this.state.percent} showInfo={false} strokeColor={this.state.imageUploading ? '#337DFF' : '#E53232'} />
                                  : null
                              }
                            </div>
                            {
                              !this.state.status
                                ? <img src={require('@/images/chaincode/reload.svg')} className="reload" onClick={this.onChangeUploadContract} />
                                : null}
                            <img src={require('@/images/chaincode/行删除.svg')} className="remove-image" onClick={() => {
                              document.getElementById('uploadInput').value = ''
                              this.form && this.form.setFieldsValue({ path: '' })
                              this.setState({
                                fileList: null,
                              })
                            }} />
                          </div>
                          : null
                      }
                    </div>
                  </Form.Item>
                </Form.Item>
              }
              {/* 部署&&升级 */}
              {
                ['deploy', 'upgrade'].includes(this.flag) &&
                <Form.Item
                  label="私有数据集："
                  name="collectionIds"
                >
                  <Select
                    mode="multiple"
                    placeholder="请选择私有数据集"
                    showArrow={true}
                    showSearch={false}
                  >
                    {
                      this.state.privateList.map(element => {
                        return (
                          <Option key={element.id} value={element.id}>{element.name}</Option>
                        )
                      })
                    }
                  </Select>
                </Form.Item>
              }
            </Form>
        }
      </Modal >
    )
  }

  chaincodeColumns = [
    {
      title: '合约名称',
      dataIndex: 'display_name',
      key: 'display_name',

    },
    { title: '标识', dataIndex: 'name', key: 'name' },
    { title: '安装节点数', dataIndex: 'nodeNum', key: 'nodeNum' },
    { title: '部署通道数', dataIndex: 'channelNum', key: 'channelNum' },
    {
      title: '版本',
      key: 'version',
      dataIndex: 'version',
    },
    {
      title: '操作', dataIndex: 'operation', key: 'operation', render: (text, record, index) => (
        <div className="action" id={`popver${index}`} style={{ position: 'relative' }}>
          {
            checkPermission('fabric-chaincode-install') &&
            <span className="common-operation"
              onClick={() => this.setModal(record, 'install', chaincode.peerList.format({ consortiumId: this.consortiumId, chaincodeId: record.id }), 'peerData')}>
            安装
            </span>
          }
          <Popover
            placement="bottom"
            overlayClassName="handle-popover"
            content={
              <div className="popover-handle-content">
                {
                  checkPermission('fabric-chaincode-deploy') &&
                  <p
                    onClick={() => this.setModal(record, 'deploy', chaincode.channelList.format({ consortiumId: this.consortiumId, chaincodeId: record.id }), 'channelData')}
                    className="popover-handle-item primary cursor">
                  部署
                  </p>
                }
                {
                  checkPermission('fabric-chaincode-upgrade') &&
                  <p
                    onClick={() => this.setModal(record, 'upgrade', chaincode.upgradeChannelList.format({ consortiumId: this.consortiumId, chaincodeId: record.id, version: record.version }), 'channelData')}
                    className="popover-handle-item primary cursor">
                  升级
                  </p>
                }
                {
                  checkPermission('fabric-chaincode-delete') &&
                   <p className="popover-handle-item primary cursor" onClick={() => this.deleteCode(record)}>
                   删除
                   </p>
                }
              </div>
            }
          >
            <span className="common-operation">更多
              <IconFont style={{ marginLeft: '4px' }} className="cursor" type="ic-down" />
            </span>
          </Popover>
        </div>
      ),
    },
  ]

  logsColumns = [
    {
      title: '时间',
      dataIndex: 'timestamp',
      key: 'timestamp',
      render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
    },
    {
      title: '事件',
      key: 'action',
      dataIndex: 'action',
      width: 170,
      render: (text, record) => {
        let obj = {
          'INSTALLED': {
            className: 'operation-success',
            text: `安装至${record.target}节点成功`,
          },
          'DEPLOYED': {
            className: 'operation-success',
            text: `部署至${record.target}节点成功`,
          },
          'UPGRADED': {
            className: 'operation-success',
            text: `升级至${_.get(this.record, 'version')}版本成功`,
          },
          'INSTALL_FAILED': {
            className: 'operation-failed',
            text: `安装至${record.target}节点失败`,
          },
          'DEPLOY_FAILED': {
            className: 'operation-failed',
            text: `部署至${record.target}节点失败`,
          },
          'UPGRADED_FAILED': {
            className: 'operation-failed',
            text: `升级至${_.get(this.record, 'version')}版本失败`,
          },
        }
        return (
          <div className="log-display">
            {
              obj[text]
                ? <div className={obj[text].className}>
                  {obj[text].text}
                </div>
                : ''
            }
          </div>
        )
      },
    },
    {
      title: '代码',
      dataIndex: 'log',
      key: 'log',
      align: 'center',
      width: 398,
      render: (text) => <span style={{ textAlign: 'left', display: 'inline-block', wordBreak: 'break-all' }} className="message">{text}</span>,
    },
  ]

  expandedRowRender = (outerRecord, index, indent, expanded) => {
    const columns = [
      {
        title: '通道名称',
        key: 'channelName',
        // width: "15%",
        dataIndex: 'channelName',
        render: (text) => <span>{text || '-'}</span>,
      },
      {
        // width: "22%",
        title: '节点名称', key: 'nodes', dataIndex: 'nodes', render: (text) => (
          <div className="peers">
            {text || '-'}
          </div>
        ),
      },
      {
        // width: "12%",
        title: '链码ID',
        dataIndex: 'id',
        key: 'id',
        render: (text, row) => {
          return (
            <span id={`tooltip${text}`} style={{ cursor: 'pointer' }}>
              <Tooltip
                getPopupContainer={() => document.getElementById(`tooltip${text}`)}
                trigger="hover"
                overlayClassName="tooltip-chaincode"
                placement="topLeft"
                title={text}>
                <span>{text && text.slice(0, 10) + '...'}</span>
              </Tooltip>
            </span>
          )
        },
      },
      {
        title: '部署时间',
        dataIndex: 'createTime',
        key: 'createTime',
        render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      },
      {
        title: '该通道合约状态', key: 'status', dataIndex: 'status', render: (text, innerRecord) => {
          if (outerRecord.status === 'DELETING') {
            // 链码被删除
            return <div className="deploy-failed contract-status">
              <div className="circle"></div>
              <div className="show-text">
                删除中
              </div>
            </div>
          }
          let obj = {
            'READY': {
              className: 'ready',
              text: '就绪',
            },
            'INSTALLING': {
              className: 'pending',
              text: '安装中',
            },
            'UPGRADING': {
              className: 'pending',
              text: '升级中',
            },
            'INSTALLED': {
              className: 'yet-install',
              text: '已安装未部署',
            },
            'DEPLOYING': {
              className: 'pending',
              text: '部署中',
            },
            'DEPLOYED': {
              className: 'yet-deploy',
              text: '已部署',
            },
            'UPGRADED': {
              className: 'yet-upgrade',
              text: `已升级至${innerRecord.version}版本`,
            },
            'INSTALL_FAILED': {
              className: 'install-failed',
              text: `安装失败`,
              onClick: true,
            },
            'DEPLOY_FAILED': {
              className: 'deploy-failed',
              text: `部署失败`,
              onClick: true,
            },
            'UPGRADED_FAILED': {
              className: 'upgrade-failed',
              text: `升级失败`,
              onClick: true,

            },
          }
          text = text || 'READY'
          return (
            obj[text] &&
            <div className={`${obj[text].className} contract-status`} onClick={() => obj[text].onClick && this.setModal(innerRecord, 'logs', chaincode.logs.format({ chaincodeId: innerRecord.id }), 'logList')}>
              <div className="circle"></div>
              <div className="show-text">
                {obj[text].text}
              </div>
            </div>
          )
        },
      },
    ]
    const { expandObj } = this.state
    return (
      <div>
        <Table
          className="chaincode-wrapper"
          columns={columns}
          dataSource={expandObj[outerRecord.id] || []}
          pagination={false}
          rowKey="id"
        />
      </div >
    )
  }

  render() {
    const { list, fileVisible, pageNo, pageSize, total, loading } = this.state

    return (
      <div id="chaincode-page" className="common chaincode-page">
        {this.renderModal()}
        <div className="chaincode-header">
          <div className="chaincode-button">
            {
              checkPermission('fabric-chaincode-add') &&
              <Button type="primary"
                onClick={() => this.setModal({}, 'addChaincode', '', 'servicesList')}
              >
              添加链码
              </Button>
            }
            {
              checkPermission('fabric-chaincode-strategy') &&
              <Button style={{ marginLeft: '8px' }}
                onClick={() => { this.props.history.push(`/dashboard/fabric/leagueInfo/${this.consortiumId}/${this.props.match.params.name}/policyManagement`) }}
              >
              策略管理
              </Button>
            }
          </div>
          <SearchInput
            placeholder="请输入合约名"
            search={this.search}
          />
        </div>
        <div style={{ position: 'relative', zIndex: 1 }}>
          <Table
            columns={this.chaincodeColumns}
            loading={loading}
            getPopupContainer={node => {
              if (node) {
                return node.parentNode
              }
              return document.body
            }}
            onChange={this.handleTableChange}
            onExpand={this.onExpand}
            expandedRowRender={this.expandedRowRender}
            className={list.length ? '' : 'empty-list'}
            dataSource={list}
            rowKey="id"
            pagination={false}
            locale={{
              emptyText: <div />,
            }}
          />
          {
            !list.length &&
              <Empty />
          }
        </div>
        <div className="pagination-box" style={{ marginBottom: '30px' }}>
          {
            list.length > 0 &&
              <Pagination
                current={pageNo}
                pageSize={pageSize}
                total={total}
                showSizeChanger
                showQuickJumper
                onShowSizeChange={this.onShowSizeChange}
                onChange={this.changePaginationFn} />
          }
        </div>
        <Modal
          centered
          destroyOnClose
          className={'fileEdit parentClass'}
          getContainer={() => document.getElementById('chaincode-page')}
          wrapClassName={`fileEdit`}
          title={'创建文件'}
          width={500}
          onCancel={() => this.setState({ fileVisible: false })}
          visible={fileVisible}
          onOk={this.saveFile}
        >
          <Form
            ref={ref => this.editForm = ref}
            {...{
              labelCol: { span: 6 },
              wrapperCol: { span: 18 },
            }}
          >
            <Form.Item
              label="文件名："
              colon={true}
              name="filename"
              rules={[
                { required: true, message: '请输入文件名' },
              ]}>
              <Input placeholder="请输入文件名" maxLength={25} addonAfter={'.go'} />
            </Form.Item>
          </Form>
          <CodeEdit ref={c => this.CodeEdit = c} />
        </Modal>
      </div>
    )
  }
}

